package com.yami.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.RefundStatusEnum;
import com.yami.shop.bean.event.RefundInfoEvent;
import com.yami.shop.bean.model.PayInfo;
import com.yami.shop.bean.model.RefundInfo;
import com.yami.shop.bean.param.CustomerReqParam;
import com.yami.shop.bean.pay.RefundInfoDto;
import com.yami.shop.bean.vo.AccountDetailVO;
import com.yami.shop.bean.vo.ShopAccountDetailVO;
import com.yami.shop.bean.vo.ShopAccountVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.enums.PayType;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.PayInfoMapper;
import com.yami.shop.dao.RefundInfoMapper;
import com.yami.shop.manager.impl.PayManager;
import com.yami.shop.service.RefundInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 *
 *
 * @author Citrus
 * @date 2022-05-25 15:45:45
 */
@Service
public class RefundInfoServiceImpl extends ServiceImpl<RefundInfoMapper, RefundInfo> implements RefundInfoService {

    @Autowired
    private RefundInfoMapper refundInfoMapper;
    @Autowired
    private PayInfoMapper payInfoMapper;
    @Autowired
    private PayManager payManager;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Boolean doRefund(RefundInfoDto refundInfoDto) {
        if (count(new LambdaQueryWrapper<RefundInfo>().eq(RefundInfo::getRefundId, refundInfoDto.getRefundSn())) > 0) {
            return false;
        }
        PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayNo, refundInfoDto.getPayNo()));
        if (Objects.isNull(payInfo)) {
            return false;
        }
        List<RefundInfo> refundInfoList = new ArrayList<>();
        for (String refundOrderNumber : refundInfoDto.getRefundOrderNumbers()) {
            RefundInfo refundInfo = new RefundInfo();
            refundInfo.setRefundId(refundInfoDto.getRefundSn());
            refundInfo.setRefundAmount(refundInfoDto.getRefundAmount());
            refundInfo.setOrderNumber(refundOrderNumber);
            refundInfo.setPayNo(refundInfoDto.getPayNo());
            refundInfo.setPayType(payInfo.getPayType());
            refundInfo.setUserId(payInfo.getUserId());
            refundInfo.setRefundStatus(RefundStatusEnum.APPLY.value());
            refundInfoList.add(refundInfo);
        }
        // 保存退款信息 refund_id是唯一的，所以能确保只进行一次退款
        saveBatch(refundInfoList);

        RefundInfoDto returnRefundInfo = new RefundInfoDto();
        returnRefundInfo.setPayNo(refundInfoDto.getPayNo());
        returnRefundInfo.setRefundSn(refundInfoDto.getRefundSn());
        returnRefundInfo.setPayType(PayType.instance(payInfo.getPayType()));
        returnRefundInfo.setPayAmount(payInfo.getPayAmount());
        returnRefundInfo.setRefundAmount(refundInfoDto.getRefundAmount());
        returnRefundInfo.setNotifyUrl("/order/refund/result/" + payInfo.getPayType());
        returnRefundInfo.setUserId(payInfo.getUserId());
        returnRefundInfo.setBizPayNo(payInfo.getBizPayNo());

        // 支付宝支付，直接退款都不需要回调的
        boolean refundSuccess = payManager.doRefund(returnRefundInfo);
        if (!Objects.equals(refundInfoDto.getOnlyRefund(), 1) && refundSuccess) {
            for (RefundInfo refundInfo : refundInfoList) {
                refundSuccess(refundInfo);
            }
        }
        return refundSuccess;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundSuccess(RefundInfo refundInfo) {
        // 已经退款
        if (Objects.equals(refundInfo.getRefundStatus(), RefundStatusEnum.SUCCEED.value())) {
            return;
        }
        refundInfo.setCallbackContent(refundInfo.getCallbackContent());
        refundInfo.setCallbackTime(new Date());
        refundInfo.setRefundStatus(RefundStatusEnum.SUCCEED.value());
        refundInfoMapper.update(refundInfo, new LambdaUpdateWrapper<RefundInfo>().eq(RefundInfo::getRefundId, refundInfo.getRefundId()));

        // 验证退款信息
        eventPublisher.publishEvent(new RefundInfoEvent(refundInfo));
    }

    @Override
    public AccountDetailVO getRefundAccountDetail(Date startTime, Date endTime, String shopName) {
        AccountDetailVO accountDetailVO = refundInfoMapper.getRefundAccountDetail(startTime, endTime, shopName);
        return getAccountDetailVO(accountDetailVO);
    }

    @Override
    public AccountDetailVO getPlatformRefundAccountDetail(Date startTime, Date endTime) {
        AccountDetailVO platformRefundAccountDetail = refundInfoMapper.getPlatformRefundAccountDetail(startTime, endTime);
        return getAccountDetailVO(platformRefundAccountDetail);
    }

    @Override
    public AccountDetailVO getAccountDetailVO(AccountDetailVO accountDetailVO) {
        if (Objects.isNull(accountDetailVO)){
            AccountDetailVO accountDetail = new AccountDetailVO();
            accountDetail.setWechatAmount(0.0);
            accountDetail.setAlipayAmount(0.0);
            accountDetail.setBalanceAmount(0.0);
            accountDetail.setPaypalAmount(0.0);
            accountDetail.setXspayAmount(0.0);
            accountDetail.setScoreCount(0L);
            accountDetail.setWechatPercent(0.00);
            accountDetail.setAlipayPercent(0.00);
            accountDetail.setBalancePercent(0.00);
            accountDetail.setPaypalPercent(0.00);
            accountDetail.setXspayPercent(0.00);
            accountDetail.setTotal(0.0);
            return accountDetail;
        } else {
            double wechatAmount = accountDetailVO.getWechatAmount();
            double alipayAmount = accountDetailVO.getAlipayAmount();
            double balanceAmount = accountDetailVO.getBalanceAmount();
            double paypalAmount = accountDetailVO.getPaypalAmount();
            double xspayAmount = accountDetailVO.getXspayAmount();
            double total = Arith.add(Arith.add(Arith.add(Arith.add(wechatAmount, alipayAmount), balanceAmount), paypalAmount),xspayAmount);
            accountDetailVO.setTotal(total);
            accountDetailVO.setWechatPercent(Arith.div(wechatAmount, total,4));
            accountDetailVO.setAlipayPercent(Arith.div(alipayAmount, total,4));
            accountDetailVO.setBalancePercent(Arith.div(balanceAmount, total,4));
            accountDetailVO.setPaypalPercent(Arith.div(paypalAmount, total, 4));
            accountDetailVO.setXspayPercent(Arith.div(xspayAmount, total, 4));
            return accountDetailVO;
        }
    }

    @Override
    public IPage<ShopAccountVO> listRefundAccountDetail(PageParam<ShopAccountVO> page, CustomerReqParam accountSearchDTO) {
        return refundInfoMapper.pageAllRefundAccount(page, accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getShopName());
    }

    @Override
    public IPage<ShopAccountDetailVO> pageShopRefundAccountDetail(PageParam<ShopAccountDetailVO> page, CustomerReqParam customerReqParam) {
        IPage<ShopAccountDetailVO> accountDetailPage;
        if (Objects.equals(customerReqParam.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            accountDetailPage = refundInfoMapper.pagePlatformRefundAccountDetail(page, customerReqParam.getStartTime(), customerReqParam.getEndTime());
        } else {
            accountDetailPage = refundInfoMapper.pageShopRefundAccountDetail(page, customerReqParam.getStartTime(), customerReqParam.getEndTime(), customerReqParam.getShopId());
        }
        return accountDetailPage;
    }

    @Override
    public List<ShopAccountDetailVO> listRefundAccountDetail(CustomerReqParam customerReqParam) {
        return refundInfoMapper.listRefundAccountDetail(customerReqParam.getStartTime(), customerReqParam.getEndTime(), customerReqParam.getShopName());
    }
}
